package org.jing.ext.spring.component;

import org.jing.core.lang.JingException;
import org.jing.core.logger.JingLogger;
import org.jing.core.util.StringUtil;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * Description: Socket服务端底层类 <br>
 * 继承的子类需要标注@Component注解交给springboot做管理 <br>
 *
 * @author bks <br>
 * @since 2023-01-28 <br>
 * @see org.jing.ext.spring.component.ExampleSocketServerStarter
 */
@Deprecated
public abstract class BaseSocketServerStarter implements ApplicationRunner {
    private static final JingLogger LOGGER = JingLogger.getLogger(BaseSocketServerStarter.class);

    @Resource private ApplicationContext context;

    public abstract String getName();

    public abstract int getPort();

    public int getPermit() {
        return Integer.MAX_VALUE;
    }

    public abstract Class<? extends BaseSocketDispatcher> getSocketClass();

    @Override public void run(ApplicationArguments args) throws Exception {
        String name = getName();
        int port = getPort();
        int permit = getPermit();
        Class<? extends BaseSocketDispatcher> socketClass = getSocketClass();
        ServerSocket server = new ServerSocket(port);
        ExecutorService executor = Executors.newCachedThreadPool();
        LOGGER.imp("[{}] start with [port: {}][permits: {}]", name, port, permit);
        Semaphore semaphore = new Semaphore(permit);
        boolean flag = true;
        while (flag) {
            Socket client = server.accept();
            BaseSocketDispatcher socketServer = getSocketDispatcher(socketClass);
            socketServer.init(client, semaphore);
            executor.execute(socketServer);
        }
        executor.shutdown();
        server.close();
    }

    private BaseSocketDispatcher getSocketDispatcher(Class<? extends BaseSocketDispatcher> socketClass) {
        Component component = socketClass.getAnnotation(Component.class);
        if (null == component) {
            throw new JingException("socket server must be annotated by Component.class");
        }
        String name = component.value();
        if (StringUtil.isEmpty(name)) {
            name = socketClass.getSimpleName();
            name = name.substring(0, 1).toLowerCase() + name.substring(1);
        }
        return context.getBean(name, socketClass);
    }
}
